package club.itstudio.IContainer.controller.teacher;

import club.itstudio.IContainer.annotation.LoginRequired;
import club.itstudio.IContainer.annotation.TeacherRequired;
import club.itstudio.IContainer.container.ContainerNetwork;
import club.itstudio.IContainer.entity.Course;
import club.itstudio.IContainer.entity.CourseExperiment;
import club.itstudio.IContainer.entity.Image;
import club.itstudio.IContainer.entity.User;
import club.itstudio.IContainer.exception.BaseException;
import club.itstudio.IContainer.exception.ParamInvalidException;
import club.itstudio.IContainer.exception.PermissionException;
import club.itstudio.IContainer.service.AuthService;
import club.itstudio.IContainer.service.CourseExperimentService;
import club.itstudio.IContainer.service.CourseService;
import club.itstudio.IContainer.service.ImageService;
import club.itstudio.IContainer.util.Result;
import club.itstudio.IContainer.util.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/teacher/experiment")
public class TeacherExperimentController {

    private CourseExperimentService courseExperimentService;
    private ImageService imageService;
    private CourseService courseService;
    private AuthService authService;
    private ContainerNetwork containerNetwork;
    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Autowired
    public void setContainerNetwork(ContainerNetwork containerNetwork) {
        this.containerNetwork = containerNetwork;
    }

    @Autowired
    public void setCourseExperimentService(CourseExperimentService courseExperimentService) {
        this.courseExperimentService = courseExperimentService;
    }

    @Autowired
    public void setImageService(ImageService imageService) {
        this.imageService = imageService;
    }

    @Autowired
    public void setCourseService(CourseService courseService) {
        this.courseService = courseService;
    }

    @Autowired
    public void setAuthService(AuthService authService) {
        this.authService = authService;
    }

    @LoginRequired
    @TeacherRequired
    @PostMapping
    public Result createNewExperiment(@RequestParam String experimentName, @RequestParam String description,
                                      @RequestParam int imageID, @RequestParam int containerAliveTime,
                                      @RequestParam int memoryLimit, @RequestParam int cpuSetLimit,
                                      @RequestParam int cpuShare, @RequestParam long endTime,
                                      @RequestParam int courseID) throws IOException {
        // 基础参数检查
        if (experimentName == null || experimentName.isEmpty() || experimentName.length() > 50) throw new ParamInvalidException();
        if (description == null || description.isEmpty() || description.length() > 200) throw new ParamInvalidException();
        if (containerAliveTime < 0 || memoryLimit < 0 || cpuSetLimit < 0 ||
                cpuShare < 0 || endTime < System.currentTimeMillis()) throw new ParamInvalidException();


        User teacher = authService.threadLocalUsers.get();

        // 课程信息检查
        Course course = courseService.getCourseByID(courseID);
        if (course == null) throw new ParamInvalidException("课程不存在");
        // 课程所有者不属于此人
        if (course.teacherID != teacher.id) throw new PermissionException();

        // 镜像信息检查
        Image image = imageService.getByImageID(imageID);
        if (image == null) throw new ParamInvalidException("image不存在");
        // 镜像未公开且镜像所有者不属于此人
        if (image.open == 0 && image.userID != teacher.id) throw new PermissionException();

        // 分配子网
        String subnet = courseExperimentService.subnetAllocate();
        if (subnet.isEmpty()) throw new BaseException("实验数量过多，无法分配子网");

        CourseExperiment experiment = new CourseExperiment();
        experiment.experimentName = experimentName;
        experiment.description = description;
        experiment.courseID = courseID;
        experiment.imageID = imageID;
        experiment.containerAliveTime = containerAliveTime;
        experiment.memoryLimit = memoryLimit;
        experiment.cpuShareLimit = cpuShare;
        experiment.cpuSetLimit = cpuSetLimit;
        experiment.endTime = endTime;
        experiment.networkName = String.valueOf(System.currentTimeMillis());
        experiment.subnet = subnet;

        //创建子网，保存到数据库
        containerNetwork.Create("bridge", experiment.subnet, experiment.networkName);
        boolean success = courseExperimentService.insert(experiment);

        if (!success) {
            return ResultUtil.error("创建实验失败，请稍后再试");
        }
        return ResultUtil.success();
    }

    @GetMapping
    @LoginRequired
    @TeacherRequired
    public Result getExperiments(@RequestParam int courseID) {
        Course course = courseService.getCourseByID(courseID);
        if (course == null) throw new ParamInvalidException();

        User teacher = authService.threadLocalUsers.get();
        if (course.teacherID != teacher.id) throw new PermissionException();

        List<CourseExperiment> experiments = courseExperimentService.getByCourseID(courseID);
        return ResultUtil.success(experiments);
    }


    @GetMapping("/student")
    @LoginRequired
    @TeacherRequired
    public Result getStudentsInExperiment(@RequestParam int experimentID, @RequestParam int courseID) {
        String sql = "SELECT\n" +
                "\tuser_list.*,\n" +
                "\tcontainer_list.container_name,\n" +
                "\tcontainer_list.created_time,\n" +
                "\tcontainer_list.end_time,\n" +
                "\tcontainer_list.`status`,\n" +
                "\tcontainer_list.ssh_port,\n" +
                "\tcontainer_list.ssh_password \n" +
                "FROM\n" +
                "\t( SELECT `user`.username, user_id FROM ( SELECT user_id FROM student_course WHERE course_id = ? ) AS user_id_list JOIN `user` ON user_id_list.user_id = `user`.id ) AS user_list\n" +
                "\tLEFT JOIN ( SELECT * FROM container WHERE experiment_id = ? ) AS container_list ON container_list.user_id = user_list.user_id";

        List<HashMap<String, Object>> data = jdbcTemplate.query(sql, (resultSet, i) -> {
            HashMap<String, Object> res = new HashMap<>();
            res.put("username", resultSet.getString("username"));
            res.put("user_id", resultSet.getInt("user_id"));
            if (resultSet.getString("container_name") != null) {
                String[] columnNames = new String[]{"container_name", "created_time", "end_time",
                        "status", "ssh_port", "ssh_password"};
                for (String columnName : columnNames) {
                    res.put(columnName, resultSet.getObject(columnName));
                }
            }
            return res;
        }, courseID, experimentID);

        return ResultUtil.success(data);
    }
}
